﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Zhao.Common.Helper
{
    /// <summary>
    /// AES-GCM 加密封装类（支持 256 位密钥）
    /// </summary>
    public class AesGcmHelper
    {
        /// <summary>
        /// 密钥
        /// </summary>
        private readonly byte[] _key;


        /// <summary>
        /// 构造函数，传入 32 字节（256 位）密钥
        /// </summary>
        /// <param name="key">密钥</param>
        /// <exception cref="ArgumentException"></exception>
        public AesGcmHelper(byte[] key)
        {
            if (key == null || key.Length != 32)
                throw new ArgumentException("AES-GCM 需要 256 位密钥（32 字节）");
            _key = key;
        }


        /// <summary>
        /// 使用 AES-GCM 加密指定的明文字符串，返回拼接后的 Base64 编码字符串。
        /// 拼接格式为：IV（12字节） + 密文 + Tag（认证标签，16字节）。
        /// </summary>
        /// <param name="plaintext">需要加密的 UTF-8 编码的明文字符串。</param>
        /// <returns>加密后的 Base64 字符串，内部包含 IV、密文和 Tag 的拼接内容。</returns>
        public string EncryptToBase64(string plaintext)
        {
            // 1. 将明文字符串转换为字节数组（UTF-8 编码）
            byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);

            // 2. 生成随机 IV（初始化向量），长度为 12 字节（AES-GCM 推荐长度）
            byte[] iv = new byte[12];
            RandomNumberGenerator.Fill(iv); // 使用安全随机数填充

            // 3. 为密文和认证标签分配空间
            byte[] ciphertext = new byte[plaintextBytes.Length]; // 密文长度与明文相同
            byte[] tag = new byte[16]; // 认证标签（Tag），长度固定为 16 字节（128-bit）

            // 4. 使用 AES-GCM 加密
            using AesGcm aes = new(_key); // _key 为 256-bit 对称密钥
            aes.Encrypt(iv, plaintextBytes, ciphertext, tag); //加密算法中会直接修改ciphertext和tag

            // 5. 将 IV + 密文 + Tag 拼接为一个字节数组
            byte[] combined = new byte[iv.Length + ciphertext.Length + tag.Length];
            Buffer.BlockCopy(iv, 0, combined, 0, iv.Length); // 拷贝 IV 到开头
            Buffer.BlockCopy(ciphertext, 0, combined, iv.Length, ciphertext.Length); // 拷贝密文
            Buffer.BlockCopy(tag, 0, combined, iv.Length + ciphertext.Length, tag.Length); // 拷贝 Tag

            // 6. 返回 Base64 编码的密文（用于存储或传输）
            return Convert.ToBase64String(combined);
        }



        /// <summary>
        /// 解密 Base64 编码的 AES-GCM 加密字符串，返回解密后的原始明文。
        /// 输入字符串必须为拼接格式：IV（12字节） + 密文 + Tag（16字节）。
        /// </summary>
        /// <param name="base64Data">Base64 编码的密文（包含 IV、密文和认证标签）。</param>
        /// <returns>解密后的 UTF-8 编码明文字符串。</returns>
        public string DecryptFromBase64(string base64Data)
        {
            // 1. 从 Base64 编码中还原字节数组
            byte[] combined = Convert.FromBase64String(base64Data);

            // 2. 提取 IV、密文、Tag
            byte[] iv = new byte[12];  // 初始化向量
            byte[] tag = new byte[16]; // 认证标签

            // 密文长度 = 总长度 - IV长度 - Tag长度
            byte[] ciphertext = new byte[combined.Length - iv.Length - tag.Length];

            // 3. 分别从拼接数组中拷贝 IV、密文、Tag 到对应变量
            Buffer.BlockCopy(combined, 0, iv, 0, iv.Length); // 取出 IV
            Buffer.BlockCopy(combined, iv.Length, ciphertext, 0, ciphertext.Length); // 取出密文
            Buffer.BlockCopy(combined, iv.Length + ciphertext.Length, tag, 0, tag.Length); // 取出 Tag

            // 4. 为解密后的明文字节数组分配空间
            byte[] decryptedBytes = new byte[ciphertext.Length];

            // 5. 执行解密，同时校验 Tag（用于验证密文完整性）
            using AesGcm aes = new(_key); // _key 为 256-bit 对称密钥
            aes.Decrypt(iv, ciphertext, tag, decryptedBytes);//decryptedBytes 会被写入解密结果,其他参数不被修改

            // 6. 将明文字节数组转换为 UTF-8 编码的字符串并返回
            return Encoding.UTF8.GetString(decryptedBytes);
        }

    }
}
